/*
    KMC Simulation
    Copyright (c) 2012-2014 Filip Rozbořil

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include "includes.h"
#include "constants.h"
#include "Event.h"
#include "ProxyEvent.h"
#include "HopRate.h"
#include "Grid.h"
#include "Random.h"

template<Direction::type D>
class HopEvent : public ProxyEvent
{
	private:
		HopRate* mHopRate;
		Grid &mGrid;
		Site::type mFrom, mTo;
		
  	protected:
		virtual void execute(Random* r);

	public:
		HopEvent(Site::type from, Site::type to, Grid &g);
		~HopEvent() { delete mHopRate; }
		virtual string getName() { return string("Hop event ") + Direction::getName(D) + " from " + Site::getName(mFrom) + " site to " + Site::getName(mTo) + " site"; }
		virtual bool updateRate() 
		{ 
			if(mHopRate->countChanged()) 
			{ 
				setRate(mHopRate->getRate()); 
				mHopRate->resetCounter(); 
				return true; 
			} 
			return false; 
		}
		virtual void printCount(ostream& os) { Event::printCount(os); }
};

template<Direction::type D>
HopEvent<D> :: HopEvent(Site::type from, Site::type to, Grid &g) : ProxyEvent(), mGrid(g), mFrom(from), mTo(to)
{
	mHopRate = new HopRate(mGrid.calculateFrequency(from, to, D), from, to, D, mGrid.getListCapacity());
	mGrid.addHopRate(mHopRate);
}

template<Direction::type D>
inline void HopEvent<D> :: execute(Random* r)
{
	auto atom = mHopRate->getAtom(r);
	mGrid.removeAtom(atom);
	mGrid.placeAtom(atom, mGrid.getField(atom->getPosition(), D));
}

